#include "AwesomeUsart.h"

/* software init */ 
unsigned char awesome_usart_init(awesome_usart* puart, unsigned char* prx, unsigned int rxcap, unsigned char* ptx, unsigned int txcap){
	
	if( puart==(void*)0 || prx==(void*)0 || ptx==(void*)0 ) return 0;
	
	#if (AWESOME_USART_DEBUG==1)
		puart->rx_error = 0;
	  puart->tx_error = 0;
	#endif
	
	puart->rxCapacity = rxcap;
	puart->txCapacity = txcap;
	puart->prxdata = prx;
	puart->ptxdata = ptx;
	puart->rxDataCount = 0;
	puart->rxReadDataPos = 0;
	puart->rxWriteDataPos = 0;
	puart->txDataCount = 0;
	puart->txReadDataPos = 0;
	puart->txWriteDataPos = 0;
	
	puart->can_read = can_read;
	puart->can_write = can_write;
	puart->write = write;
	puart->writes = writes;
	puart->read = read;
	puart->reads = reads;
	
	puart->low_set_read_buff = low_set_read_buff;	
	puart->low_get_write_buff = low_get_write_buff;
	
	return 1;
}

/* usart rx data buff is full: return can send data count */ 
unsigned int can_read(awesome_usart* puart){
	
	if( puart==(void*)0 ) return 0;
	
	if( puart->rxCapacity<=0 ) return 0;
	
	return puart->rxDataCount;	
}

/* usart tx data buff is full: return can rx data count */ 
unsigned int can_write(awesome_usart* puart){
	
	if( puart==(void*)0 ) return 0;
	
	if( puart->txCapacity<=0 ) return 0;
	
	if( puart->txDataCount>=puart->txCapacity ) return 0;	
	else return puart->txCapacity-puart->txDataCount;
	
}

/* data write send data buff */ 
unsigned char write(awesome_usart* puart, unsigned char data){
	
	if( puart==(void*)0 ) return 0;
	
	CLOSE_IRP();
	if( can_write(puart)>0 ){
		puart->txWriteDataPos = puart->txWriteDataPos%puart->txCapacity;
		puart->ptxdata[puart->txWriteDataPos] = data;
		++puart->txWriteDataPos;
		++puart->txDataCount;
		OPEN_IRP();
		#if (AWESOME_USART_DEBUG==1)
	  puart->tx_error = 0;
		#endif
		return data;		
	}else{
		#if (AWESOME_USART_DEBUG==1)
	  puart->tx_error = 1;
		#endif
	}
	OPEN_IRP();
	
	return 0;	
}

/* data write send data buff, none return 0, other return data len  */ 
unsigned int writes(awesome_usart* puart, unsigned char* data, unsigned int len){
	
	unsigned int i = 0;
	
	if( puart==(void*)0 || data==(void*)0 || len<=0 ) return 0;
	
	CLOSE_IRP();
	
	if(can_write(puart)==0) {
		#if (AWESOME_USART_DEBUG==1)
	  puart->tx_error = 1;
		#endif
		OPEN_IRP();
		return (char)0;
	}
	
	//if(awesome_usartCanWrite(puart)<len) len = awesome_usartCanWrite(puart);
	if(can_write(puart)<len) {
		#if (AWESOME_USART_DEBUG==1)
	  puart->tx_error = 1;
		#endif
		OPEN_IRP();
		return 0;
	}
	
	#if (AWESOME_USART_DEBUG==1)
	  puart->tx_error = 0;
	#endif
	
	for( ; i<len; ++i){
		puart->txWriteDataPos = puart->txWriteDataPos%puart->txCapacity;
		puart->ptxdata[puart->txWriteDataPos] = data[i];
		++puart->txWriteDataPos;
		
		++puart->txDataCount;	
		
	}
	OPEN_IRP();
	return len;		
}

/* usart read data from data buff, read success=data len, other 0*/
unsigned int reads(awesome_usart* puart, unsigned char* data, unsigned int len){
	
	unsigned int reslen = 0;
	unsigned int i = 0;
	unsigned int havelen;
	
	if( puart==(void*)0 || len<=0 || data==(void*)0 ) return 0;
	
		
	CLOSE_IRP();
	havelen = can_read(puart);
	
	if(havelen==0) { 
		OPEN_IRP();
		return 0; 
	}
	
	if(havelen<=len) len = havelen;
	
	reslen = len;

	for( i=0; i<len; i++){
		puart->rxReadDataPos = puart->rxReadDataPos%puart->rxCapacity;		
		data[i] = puart->prxdata[puart->rxReadDataPos%puart->rxCapacity];
		++puart->rxReadDataPos;
		
		--puart->rxDataCount;
	}
	OPEN_IRP();
	
	return reslen;	
} 

/* read a data, need call awesome_usartCanRead() before get data len: success=1, other=-1*/ 
unsigned char read(awesome_usart* puart){
		
  unsigned int havelen;
	unsigned char data;
	
	if( puart==(void*)0 ) return 0;
	
	CLOSE_IRP();
	havelen = can_read(puart);
	if(havelen==0) { 
		OPEN_IRP();
		return 0; 
	}
		
	puart->rxReadDataPos = puart->rxReadDataPos%puart->rxCapacity;
	data = puart->prxdata[puart->rxReadDataPos];
	++puart->rxReadDataPos;

	--puart->rxDataCount;
	OPEN_IRP();
	
	return (unsigned char)data;	
} 

/* Low callback: hardware usart rx data to save buff */ 
__inline char low_set_read_buff(awesome_usart* puart, unsigned char* data, unsigned int len){
	
	unsigned int i = 0;
	
	if( puart==(void*)0 || len<=0 ) return (char)-1;
	
	for( ; i<len; ++i )
	{
		if( puart->rxDataCount>=puart->rxCapacity || puart->rxCapacity<=0 ){
			#if (AWESOME_USART_DEBUG==1)
			puart->rx_error = 1;
			#endif
			return (char)-1;
		}
		#if (AWESOME_USART_DEBUG==1)
			puart->rx_error = 0;
		#endif
		
		puart->rxWriteDataPos = puart->rxWriteDataPos%puart->rxCapacity;
		puart->prxdata[puart->rxWriteDataPos] = data[i];
		++puart->rxWriteDataPos;

		CLOSE_IRP();
		++puart->rxDataCount;
		OPEN_IRP();
	}
	
	return 1;
}

__inline unsigned int low_get_write_buff(awesome_usart* puart, unsigned char* data, unsigned int len){
	
	unsigned int reslen = 0;
	unsigned int i = 0;
	unsigned int havelen;
	
	if( puart==(void*)0 || len<=0 || data==(void*)0 ) return 0;
	
	havelen = puart->txDataCount;
	
	if(havelen==0) { return 0; }
	
	if(havelen<=len) len = havelen;
	
	reslen = len;
	
	for( i=0; i<len; i++){
		puart->txReadDataPos = puart->txReadDataPos%puart->txCapacity;
		data[i] = puart->ptxdata[puart->txReadDataPos];
		++puart->txReadDataPos;
		
		CLOSE_IRP();
		--puart->txDataCount;
		OPEN_IRP();
	}
	
	return reslen;			
}
